<?php

declare(strict_types=1);
/**
 * This file is part of habo_new_media.
 *
 * @link     https://www.berlen.cn/
 * @contact  tech@berlen.cn
 * @license  http://gitlab.rehou.cn/habo/habo_new_media/-/blob/master/README.md
 */
namespace app\service\cdc\stat;

use app\enum\CostServiceCostEnum;
use app\model\mongo\MongoKsAccountVideoStatModel;
use app\model\mongo\MongoKsClientVideoStatModel;
use app\model\mongo\MongoKsUserVideoStatModel;
use app\model\mongo\MongoKsVideoStatModel;
use app\model\mongo\MongoReportModel;
use app\model\mongo\MongoStatModel;
use app\model\mongo\MongoSyncModel;
use app\service\cdc\sync\VideoLogService;
use app\service\cdc\VideoService;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Model;

abstract class VideoStatService extends StatService
{
    protected ?MongoSyncModel $syncModel;

    /**
     * @var null|array|mixed|Model|MongoKsVideoStatModel
     */
    protected ?MongoStatModel $statModel;

    /**
     * @var null|array|mixed|Model|MongoKsAccountVideoStatModel|MongoKsClientVideoStatModel|MongoKsUserVideoStatModel|MongoKsVideoStatModel
     */
    protected ?MongoReportModel $recordModel;

    /**
     * 初始化数据模型.
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function setModel(): bool
    {
        if (! $this->getStatModel()) {
            return false;
        }

        if (! $this->getRecordModel()) {
            return false;
        }

        return true;
    }

    /**
     * 获取汇总数据模型.
     * @return null|array|bool|mixed|Model|MongoKsVideoStatModel|MongoStatModel
     */
    public function getStatModel()
    {
        if (! in_array($this->syncModel->getAttr('type'), array_keys($this->statModelList))) {
            return self::setError('未知的统计类型');
        }

        if ($this->syncModel->getAttr('type') == CostServiceCostEnum::STAT_ACCOUNT) {
            $field = ['account_id', 'video_id'];
        } elseif ($this->syncModel->getAttr('type') == CostServiceCostEnum::STAT_CLIENT) {
            $field = ['client_id', 'video_id'];
        } elseif ($this->syncModel->getAttr('type') == CostServiceCostEnum::STAT_KS_USER_VIDEO) {
            $field = ['user_id', 'video_id'];
        } else {
            $field = ['video_id'];
        }

        $where = [];
        foreach ($field as $v) {
            if ($v == 'user_id') {
                $where[] = [$v, '=', KsVideoService::getUserIdByAccountId($this->syncModel->getAttr('account_id'))];
            } else {
                $where[] = [$v, '=', $this->syncModel->getAttr($v)];
            }
        }

        return $this->statModel = VideoService::getStatModel($this->mediaId, $this->syncModel->getAttr('type'), $where);
    }

    /**
     * @throws DataNotFoundException
     * @throws ModelNotFoundException
     * @throws DbException
     */
    public function getRecordModel()
    {
        if (! in_array($this->syncModel->getAttr('type'), array_keys($this->recordModelList))) {
            return self::setError('未知的统计类型');
        }

        $field = ['account_id', 'video_id', 'stat_date'];
        $where = [];
        foreach ($field as $v) {
            $where[] = [$v, '=', $this->syncModel->getAttr($v)];
        }

        $className = $this->recordModelList[$this->syncModel->getAttr('type')];
        $this->recordModel = (new $className())->where($where)->find();
        if (! $this->recordModel instanceof MongoReportModel) {
            $this->recordModel = new $className();
        }

        return $this->recordModel;
    }

    /*
     * 更新指定素材消耗.
     * @param Model $model 数据基础表模型
     */
    public function addStatByRecord(): bool
    {
        $fields = [];
        if (! $this->statModel->getKey()) {
            $fields = $this->getStatField();
        }
        if (! VideoService::addStat($this->statModel, $fields)) {
            return self::setError('更新统计数据失败');
        }

        if ($this->statModel->getKey()) {
            $this->statModel->inc('cost', static::getCost($this->recordModel->getAttr('cost')));

            if (! $this->statModel->save()) {
                return self::setError('更新统计数据失败');
            }
        }
        return VideoLogService::deleteLog($this->syncModel);
    }

    public function sumStat(): bool
    {
        if (! $this->statModel->getKey()) {
            $this->statModel->setAttrs($this->getSumStatField());
        }

        $statInfo = $this->getStatInfo();
        if (! $statInfo) {
            return self::setError('获取统计数据失败');
        }

        // $statInfo = $statInfo[0];
        $this->statModel->setAttr('version', $statInfo['stat_date_max']);
        $this->statModel->setAttr('cost', static::getCost(floatval($statInfo['cost_sum'])));
        $this->statModel->inc('cost', static::getCost(floatval($this->recordModel->getAttr('cost'))));
        $this->statModel->update_time = time();
        if (! $this->statModel->save()) {
            return self::setError('更新统计数据失败');
        }

        return VideoLogService::deleteLog($this->syncModel, $statInfo['stat_date_max']);
    }

    protected function getStatInfo(): array
    {
        $statDateMax = $this->recordModel->where($this->getSumStatField())->max('stat_date');
        $costSum = $this->recordModel->where($this->getSumStatField())->sum('cost');
        if (isset($statDateMax, $costSum)) {
            return ['stat_date_max' => $statDateMax, 'cost_sum' => $costSum];
        }
        return [];
    }

    /*
     * 比较版本.
     * @param Model $model 中间表模型
     */
    protected function compareStat(): int
    {
        if (! $this->statModel->getKey()) {
            return -1;
        }

        return $this->statModel->getAttr('version') < $this->syncModel->getAttr('stat_date') ? 1 : -1;
    }

    /**
     * 获取汇总字段.
     */
    protected function getStatField(): array
    {
        $fields = $this->statModel->getNeedField();
        $data = [];
        foreach ($fields as $v) {
            if ($v == 'user_id') {
                $data[$v] = static::getUserId($this->recordModel->getAttr('adv_id'));
            } elseif ($v == 'cost') {
                $data[$v] = static::getCost(floatval($this->recordModel->getAttr('cost')));
            } elseif ($v == 'version') {
                $data[$v] = $this->recordModel->getAttr('stat_date');
            } else {
                $data[$v] = $this->recordModel->getAttr($v);
            }
        }
        return $data;
    }

    /**
     * 获取和汇总字段.
     */
    protected function getSumStatField(): array
    {
        $fields = $this->statModel->getSumField();
        $data = [];

        foreach ($fields as $v) {
            $data[$v] = $this->recordModel->getAttr($v);
        }

        return $data;
    }
}
